/*
 * @Author       : wjw 3358953076@qq.com
 * @Date         : 2024-04-28 10:25:55
 * @LastEditors  : wjw 3358953076@qq.com
 * @LastEditTime : 2024-05-26 17:13:51
 * @FilePath     : \charger_controller\applications\bsp\bsp_can.c
 * @Description  : 
 * SPDX-License-Identifier: GPL-3.0
 * Copyright (c) 2024 by wjw, All Rights Reserved.
 */
#include "bsp_can.h"
#ifdef BSP_USING_CAN
#include <can.h>
#include "j1939.h"

#ifdef BSP_CAN_RT_THREAD_DRV
#include "rtthread.h"
#define DBG_TAG "bsp_can"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#endif

typedef struct bsp_can_obj_Tx
{
    CAN_TxHeaderTypeDef HAL_TxHeader;//发送数据结构体（该结构体由HAL库提供）
    uint32_t TxMailbox;//要存储发送数据的发送邮箱
}bsp_can_obj_Tx;

typedef struct bsp_can_obj_Rx
{
	CAN_RxHeaderTypeDef HAL_RxHeader;//接收数据结构体（该结构体由HAL库提供）
	uint8_t RxData[8];//接收到的数据帧数据，最大为8
}bsp_can_obj_Rx;

typedef struct _bsp_can_rx_callbacks_table 
{
	int count;
	void (*pCallbacks_tsble[BSP_CAN_RX_CALLBSCKS_COUNT_MAX])(const uint32_t id, const uint8_t* buf, const uint32_t buf_len);
}_bsp_can_rx_callbacks_table;

#define CAN1_TX_MAILBOX CAN_TX_MAILBOX0
#define CAN1_RX_MAILBOX CAN_RX_FIFO0
static bsp_can_obj_Rx bsp_can1_Rx;
static bsp_can_obj_Tx bsp_can1_Tx;
static _bsp_can_rx_callbacks_table can1_rx_callbacks_table;
#ifdef BSP_CAN2_EN
#define CAN2_TX_MAILBOX CAN_TX_MAILBOX1
#define CAN2_RX_MAILBOX CAN_RX_FIFO0
static bsp_can_obj_Rx bsp_can2_Rx;
static bsp_can_obj_Tx bsp_can2_Tx;
static _bsp_can_rx_callbacks_table can2_rx_callbacks_table;
#endif

/**
 * @brief bsp_can:CAN初始化(配置发送消息，配置筛选器绑定邮箱)，CAN1 接收邮箱0 发送邮箱0；CAN2 接收邮箱0 发送邮箱1
 * @param {Bsp_CAN_Port} canx_port CAN端口(can1_port/can2_port)
 * @return {*}
 */
void bsp_can_init(Bsp_CAN_Port canx_port)
{
	CAN_FilterTypeDef Filter;
	CAN_HandleTypeDef* pcan;
	if(canx_port == can1_port){
	    pcan = &hcan1;
	}
#ifdef BSP_CAN2_EN
	else if(canx_port == can2_port){
	    pcan = &hcan2;
    }
#endif
	if(canx_port == can1_port)
	{
        bsp_can1_Tx.HAL_TxHeader.StdId=0;//标准模式ID
        bsp_can1_Tx.HAL_TxHeader.ExtId=0;//扩展模式ID
        bsp_can1_Tx.HAL_TxHeader.IDE=CAN_ID_EXT;//选择为扩 展帧
        bsp_can1_Tx.HAL_TxHeader.RTR=CAN_RTR_DATA;//选择为数据帧
        bsp_can1_Tx.HAL_TxHeader.DLC=8;//数据帧数据长度为8个字节(！！注意遥控帧数据长度为0)
        bsp_can1_Tx.HAL_TxHeader.TransmitGlobalTime=DISABLE;//不生成时报文时间戳
        bsp_can1_Tx.TxMailbox=CAN1_TX_MAILBOX;//发送邮箱0发送消息

        Filter.FilterIdHigh=(((uint32_t)CAN1_ID<<3|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16;
        Filter.FilterIdLow=(((uint32_t)CAN1_ID<<3|CAN_ID_EXT|CAN_RTR_DATA)&0x0000FFFF);

        Filter.FilterMaskIdHigh=(((uint32_t)CAN1_IDMASK<<3|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16;
        Filter.FilterMaskIdLow=(((uint32_t)CAN1_IDMASK<<3|CAN_ID_EXT|CAN_RTR_DATA)&0x0000FFFF);
		Filter.FilterFIFOAssignment=CAN_RX_FIFO0;//接收数据存储邮箱
		Filter.FilterBank=0;//筛选器组选择(0~13)
		Filter.FilterMode=CAN_FILTERMODE_IDMASK;//掩码模式
		Filter.FilterScale=CAN_FILTERSCALE_32BIT;//32位筛选
		Filter.FilterActivation=ENABLE;//启用筛选器
		Filter.SlaveStartFilterBank=0;//因为启用的是CAN1，用不到，所以关闭
	}
#ifdef BSP_CAN2_EN
	else if(canx_port == can2_port)
	{
        bsp_can2_Tx.HAL_TxHeader.StdId=0;//标准模式ID
        bsp_can2_Tx.HAL_TxHeader.ExtId=0;//扩展模式ID
        bsp_can2_Tx.HAL_TxHeader.IDE=CAN_ID_EXT;//选择为扩展帧
        bsp_can2_Tx.HAL_TxHeader.RTR=CAN_RTR_DATA;//选择为数据帧
        bsp_can2_Tx.HAL_TxHeader.DLC=8;//数据帧数据长度为8个字节(！！注意遥控帧数据长度为0)
        bsp_can2_Tx.HAL_TxHeader.TransmitGlobalTime=DISABLE;//不生成时报文时间戳
        bsp_can2_Tx.TxMailbox=CAN2_TX_MAILBOX;//发送邮箱0发送消息

        Filter.FilterIdHigh=(((uint32_t)CAN2_ID<<3|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16;
        Filter.FilterIdLow=(((uint32_t)CAN2_ID<<3|CAN_ID_EXT|CAN_RTR_DATA)&0x0000FFFF);

        Filter.FilterMaskIdHigh=(((uint32_t)CAN2_IDMASK<<3|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16;
        Filter.FilterMaskIdLow=(((uint32_t)CAN2_IDMASK<<3|CAN_ID_EXT|CAN_RTR_DATA)&0x0000FFFF);

		Filter.FilterFIFOAssignment=CAN_RX_FIFO0;//接收数据存储邮箱
		Filter.FilterBank=14;//筛选器组选择(0~13)
		Filter.FilterMode=CAN_FILTERMODE_IDMASK;//掩码模式
		Filter.FilterScale=CAN_FILTERSCALE_32BIT;//32位筛选
		Filter.FilterActivation=ENABLE;//启用筛选器
		Filter.SlaveStartFilterBank=14;//CAN2启用从筛选器
	}
#endif
	HAL_CAN_ConfigFilter(pcan,&Filter);//CAN筛选器配置
}

/**
 * @brief bsp_can:CAN启动
 * @param {Bsp_CAN_Port} canx_port CAN端口(can1_port/can2_port)
 * @return {*}
 */
void bsp_can_start(Bsp_CAN_Port canx_port)
{
    CAN_HandleTypeDef* pcan;
    if(canx_port == can1_port){
        pcan = &hcan1;
    }
#ifdef BSP_CAN2_EN
    else if(canx_port == can2_port){
        pcan = &hcan2;
    }
#endif
	/*1.启动CAN节点*/
	HAL_CAN_Start(pcan);
	/*2.使能CAN中断*/
	HAL_CAN_ActivateNotification(pcan,CAN_IT_RX_FIFO0_MSG_PENDING);
}

/**
 * @brief bsp_can:CAN停止
 * @param {Bsp_CAN_Port} canx_port CAN端口(can1_port/can2_port)
 * @return {*}
 */
void bsp_can_stop(Bsp_CAN_Port canx_port)
{
    CAN_HandleTypeDef* pcan;
    if(canx_port == can1_port){
        pcan = &hcan1;
    }
#ifdef BSP_CAN2_EN
    else if(canx_port == can2_port){
        pcan = &hcan2;
    }
#endif
	/*1.启动CAN节点*/
	HAL_CAN_Stop(pcan);
	/*2.关闭CAN中断*/
	HAL_CAN_DeactivateNotification(pcan,CAN_IT_RX_FIFO0_MSG_PENDING);
}

/**
 * @brief bsp_can:CAN发送报文——扩展数据帧，数据长度8字节
 * @param {Bsp_CAN_Port} canx_port CAN端口(can1_port/can2_port)
 * @param {uint8_t*} pbuf 发送数据缓存(长度8个字节)
 * @param {uint32_t} buf_len 发送数据长度(长度最大8个字节)
 * @param {uint32_t*} ExdID 扩展数据帧id
 * @return {int}
 * @retval 0: 发送成功
 * @retval -1: 发送失败
 */
int bsp_can_send_message(CAN_NODE canx_port,uint8_t *pbuf,uint32_t buf_len,uint32_t ExdID)
{
    if(pbuf==NULL)return -1;
	if(canx_port == Select_CAN_NODE_1)
	{
		bsp_can1_Tx.HAL_TxHeader.ExtId = ExdID;//扩展模式ID
		bsp_can1_Tx.HAL_TxHeader.DLC = buf_len;
		//检测指定的发送邮箱是否可用	并等待
		while(HAL_CAN_IsTxMessagePending(&hcan1,CAN1_TX_MAILBOX) == 1){
#ifdef BSP_CAN_RT_THREAD_DRV
            rt_thread_delay(1);
#else
            ;
#endif
		}
		if(!HAL_CAN_IsTxMessagePending(&hcan1,CAN1_TX_MAILBOX)){
				//CAN向发送邮箱添加要发送的消息并发送出去
				HAL_CAN_AddTxMessage(&hcan1,&bsp_can1_Tx.HAL_TxHeader,pbuf,&bsp_can1_Tx.TxMailbox);
				//printf("send success!\n");
				return 0;
		}
	}
#ifdef BSP_CAN2_EN
	else if(canx_port == can2_port)
	{
		bsp_can2_Tx.HAL_TxHeader.ExtId = ExdID;//扩展模式ID
		bsp_can2_Tx.HAL_TxHeader.DLC = buf_len;
		while(HAL_CAN_IsTxMessagePending(&hcan2,CAN2_RX_MAILBOX) == 1){
#ifdef BSP_CAN_RT_THREAD_DRV
            rt_thread_delay(1);
#else
            ;
#endif
		}
		//检测指定的发送邮箱是否可用 并等待
		if(!HAL_CAN_IsTxMessagePending(&hcan2,CAN2_RX_MAILBOX)){
				//CAN向发送邮箱添加要发送的消息并发送出去
				HAL_CAN_AddTxMessage(&hcan2,&bsp_can2_Tx.HAL_TxHeader,pbuf,&bsp_can2_Tx.TxMailbox);
				return 0;
		}
	}
#endif
	return -1;
}


/**
 * @brief bsp_can:CAN添加接收回调函数(禁止在回调函数中使用任何形式的阻塞函数)
 * @param {Bsp_CAN_Port} canx_port CAN端口(can1_port/can2_port)
 * @param { void(*)(const uint32_t, const uint8_t*, const uint32_t)} pCallbacks can接收回调函数
 * @return {int}
 * @retval 0: 设置成功
 * @retval -1: 设置失败
 */
int bsp_can_add_rx_callback(CAN_NODE canx_port,void (*pCallbacks)(const uint32_t id, const uint8_t* buf, const uint32_t buf_len))
{
    if(pCallbacks==NULL)return -1;
    if(canx_port == Select_CAN_NODE_1){
        if(can1_rx_callbacks_table.count>=BSP_CAN_RX_CALLBSCKS_COUNT_MAX-1)return -1;
        can1_rx_callbacks_table.pCallbacks_tsble[can1_rx_callbacks_table.count] = pCallbacks;
        if(can1_rx_callbacks_table.count<BSP_CAN_RX_CALLBSCKS_COUNT_MAX)can1_rx_callbacks_table.count++;
    }
#ifdef BSP_CAN2_EN
    else if(canx_port == can2_port){
        if(can2_rx_callbacks_table.count>=BSP_CAN_RX_CALLBSCKS_COUNT_MAX-1)return -1;
        can2_rx_callbacks_table.pCallbacks_tsble[can2_rx_callbacks_table.count] = pCallbacks;
        if(can2_rx_callbacks_table.count<BSP_CAN_RX_CALLBSCKS_COUNT_MAX)can2_rx_callbacks_table.count++;
    }
#endif
    return 0;
}

static void _bsp_can1_rx_callbacks_table_run(const uint32_t id, const uint8_t* buf, const uint32_t buf_len)
{
    int i;
	for (i = 0; i < can1_rx_callbacks_table.count; i++) {
		can1_rx_callbacks_table.pCallbacks_tsble[i](id,buf,buf_len);
	}
}

#ifdef BSP_CAN2_EN
static void _bsp_can2_rx_callbacks_table_run(const uint32_t id, const uint8_t* buf, const uint32_t buf_len)
{
    int i;
	for (i = 0; i < can2_rx_callbacks_table.count; i++) {
		can2_rx_callbacks_table.pCallbacks_tsble[i](id,buf,buf_len);
	}
}
#endif

/**
 * @brief bsp_can:CAN接收回调函数
 * @param {CAN_HandleTypeDef*} pcan CAN_HandleTypeDef对象
 * @return 无
 */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *pcan)
{
    //CAN1接收中断
	if(pcan->Instance==CAN1){
        //RxMailbox邮箱有无数据，并读取
		if(HAL_CAN_GetRxMessage(pcan,CAN1_RX_MAILBOX,&bsp_can1_Rx.HAL_RxHeader,bsp_can1_Rx.RxData) == HAL_OK){
            _bsp_can1_rx_callbacks_table_run(bsp_can1_Rx.HAL_RxHeader.ExtId,bsp_can1_Rx.RxData,bsp_can1_Rx.HAL_RxHeader.DLC);
		}
	}
#ifdef BSP_CAN2_EN
	else if(pcan->Instance==CAN2){
		if(HAL_CAN_GetRxMessage(pcan,CAN2_RX_MAILBOX,&bsp_can2_Rx.HAL_RxHeader,bsp_can2_Rx.RxData) == HAL_OK){
		    _bsp_can2_rx_callbacks_table_run(bsp_can2_Rx.HAL_RxHeader.ExtId,bsp_can2_Rx.RxData,bsp_can2_Rx.HAL_RxHeader.DLC);
		}
	}
#endif
}

#ifdef BSP_CAN_RT_THREAD_DRV

struct rt_device drv_can1;
#ifdef BSP_CAN2_EN
struct rt_device drv_can2;
#endif

static rt_err_t drv_can_open(rt_device_t dev, rt_uint16_t oflag);
static rt_err_t drv_can_close(rt_device_t dev);
static rt_size_t drv_can_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
static rt_size_t drv_can_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
static rt_err_t  drv_can_control(rt_device_t dev, int cmd, void *args);

rt_err_t drv_can_init(rt_device_t dev)
{

    if(dev == RT_NULL)return -RT_ERROR;
    //设备类型:CAN
    dev->type = RT_Device_Class_CAN;
    dev->rx_indicate = RT_NULL;
    dev->tx_complete = RT_NULL;
    dev->init = drv_can_init;
    dev->open = drv_can_open;
    dev->close = drv_can_close;
    dev->read = drv_can_read;
    dev->write = drv_can_write;
    dev->control = drv_can_control;
    return RT_EOK;
}

static rt_err_t drv_can_open(rt_device_t dev, rt_uint16_t oflag)
{
    return RT_EOK;
}

static rt_err_t drv_can_close(rt_device_t dev)
{
    return RT_EOK;
}

static rt_size_t drv_can_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    return 0;
}

static rt_size_t drv_can_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    return 0;
}

static rt_err_t  drv_can_control(rt_device_t dev, int cmd, void *args)
{
    return RT_EOK;
}

static int drv_can1_register(void)
{
    rt_err_t ret;
    rt_device_t dev = &drv_can1;
    //初始化设备:led
    bsp_can_init(can1_port);
    drv_can_init(dev);
    //注册驱动:led 可读可写
    ret = rt_device_register(dev,"can1",RT_DEVICE_FLAG_RDWR);
    if(ret != RT_EOK)LOG_E("drv_can1_register:%d",ret);
    else LOG_I("drv_can1_register");
#ifdef BSP_CAN2_EN
    dev = &drv_can2;
    //初始化设备:led
    bsp_can_init(can2_port);
    drv_can_init(dev);
    //注册驱动:led 可读可写
    ret = rt_device_register(dev,"can2",RT_DEVICE_FLAG_RDWR);
    if(ret != RT_EOK)LOG_E("drv_can2_register:%d",ret);
    else LOG_I("drv_can2_register");
#endif
    return ret;
}
INIT_COMPONENT_EXPORT(drv_can1_register);

#endif
#endif

void CAN1_RX0_IRQHandler(void)
{
    HAL_CAN_IRQHandler(&hcan1);
}

